﻿using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using NUnit.Framework;
using ValidationFramework.WPF;

namespace ValidationFramework.Tests.WPF
{
	public class ValidationBindingTest
	{
		[TestFixture]
		public class Construction
		{
			[Test]
			public void Default()
			{
				var validationBinding = new ValidationBinding();
				Assert.IsNull(validationBinding.AsyncState);
				Assert.IsFalse(validationBinding.BindsDirectlyToSource);
				Assert.IsNull(validationBinding.Context);
				Assert.IsNull(validationBinding.Converter);
				Assert.IsNull(validationBinding.ConverterCulture);
				Assert.IsNull(validationBinding.ConverterParameter);
				Assert.IsNull(validationBinding.ElementName);
				Assert.AreEqual(DependencyProperty.UnsetValue, validationBinding.FallbackValue);
				Assert.IsFalse(validationBinding.IsAsync);
				Assert.AreEqual(BindingMode.Default, validationBinding.Mode);
				Assert.IsTrue(validationBinding.NotifyOnTargetUpdated);
				Assert.IsFalse(validationBinding.NotifyOnValidationError);
				Assert.IsNull(validationBinding.Path);
				Assert.IsNull(validationBinding.RelativeSource);
				Assert.IsNull(validationBinding.RuleSet);
				Assert.IsNull(validationBinding.Source);
				Assert.IsNull(validationBinding.UpdateSourceExceptionFilter);
				Assert.AreEqual(UpdateSourceTrigger.PropertyChanged, validationBinding.UpdateSourceTrigger);
				Assert.AreEqual(0, validationBinding.ValidationRules.Count);
				Assert.IsNull(validationBinding.XPath);
			}
			[Test]
			public void DefaultPath()
			{
				var validationBinding = new ValidationBinding("ExpectedPath");
				Assert.IsNull(validationBinding.AsyncState);
				Assert.IsFalse(validationBinding.BindsDirectlyToSource);
				Assert.IsNull(validationBinding.Context);
				Assert.IsNull(validationBinding.Converter);
				Assert.IsNull(validationBinding.ConverterCulture);
				Assert.IsNull(validationBinding.ConverterParameter);
				Assert.IsNull(validationBinding.ElementName);
				Assert.AreEqual(DependencyProperty.UnsetValue, validationBinding.FallbackValue);
				Assert.IsFalse(validationBinding.IsAsync);
				Assert.AreEqual(BindingMode.Default, validationBinding.Mode);
				Assert.IsTrue(validationBinding.NotifyOnTargetUpdated);
				Assert.IsFalse(validationBinding.NotifyOnValidationError);
				Assert.IsNotNull(validationBinding.Path);
				Assert.AreEqual("ExpectedPath", validationBinding.Path.Path);
				Assert.IsNull(validationBinding.RelativeSource);
				Assert.IsNull(validationBinding.RuleSet);
				Assert.IsNull(validationBinding.Source);
				Assert.IsNull(validationBinding.UpdateSourceExceptionFilter);
				Assert.AreEqual(UpdateSourceTrigger.PropertyChanged, validationBinding.UpdateSourceTrigger);
				Assert.AreEqual(0, validationBinding.ValidationRules.Count);
				Assert.IsNull(validationBinding.XPath);
			}
			[Test]
			public void NonDefaultRelativeSource()
			{
				var validationBinding = new ValidationBinding
				{
					AsyncState = new object(),
					BindsDirectlyToSource = true,
					Context = new object(),
					Converter = new BooleanToVisibilityConverter(),
					ConverterCulture = CultureInfo.CurrentCulture,
					ConverterParameter = new object(),
					FallbackValue = new object(),
					IsAsync = true,
					Mode = BindingMode.OneTime,
					NotifyOnTargetUpdated = true,
					NotifyOnValidationError = false,
					Path = new PropertyPath("ExpectedPath"),
					RelativeSource = RelativeSource.PreviousData,
					RuleSet = "ExpectedRuleSet",
					UpdateSourceExceptionFilter = CallBack,
					UpdateSourceTrigger = UpdateSourceTrigger.Explicit,
					XPath = "ExpectedXPath"
				};
				Assert.IsNotNull(validationBinding.AsyncState);
				Assert.IsTrue(validationBinding.BindsDirectlyToSource);
				Assert.IsNotNull(validationBinding.Context);
				Assert.IsNotNull(validationBinding.Converter);
				Assert.IsNotNull(validationBinding.ConverterCulture);
				Assert.IsNotNull(validationBinding.ConverterParameter);
				Assert.IsNull(validationBinding.ElementName);
				Assert.IsNotNull(validationBinding.FallbackValue);
				Assert.IsTrue(validationBinding.IsAsync);
				Assert.AreEqual(BindingMode.OneTime, validationBinding.Mode);
				Assert.IsTrue(validationBinding.NotifyOnTargetUpdated);
				Assert.IsFalse(validationBinding.NotifyOnValidationError);
				Assert.IsNotNull(validationBinding.Path);
				Assert.IsNotNull(validationBinding.RelativeSource);
				Assert.IsNotNull(validationBinding.RuleSet);
				Assert.IsNull(validationBinding.Source);
				Assert.IsNotNull(validationBinding.UpdateSourceExceptionFilter);
				Assert.AreEqual(UpdateSourceTrigger.Explicit, validationBinding.UpdateSourceTrigger);
				Assert.AreEqual(0, validationBinding.ValidationRules.Count);
				Assert.IsNotNull(validationBinding.XPath);
			}
			[Test]
			public void NonDefaultElementName()
			{
				var validationBinding = new ValidationBinding
				{
					AsyncState = new object(),
					BindsDirectlyToSource = true,
					Context = new object(),
					Converter = new BooleanToVisibilityConverter(),
					ConverterCulture = CultureInfo.CurrentCulture,
					ConverterParameter = new object(),
					ElementName = "ExpectedElementName",
					FallbackValue = new object(),
					IsAsync = true,
					Mode = BindingMode.OneTime,
					NotifyOnTargetUpdated = true,
					NotifyOnValidationError = false,
					Path = new PropertyPath("ExpectedPath"),
					RuleSet = "ExpectedRuleSet",
					UpdateSourceExceptionFilter = CallBack,
					UpdateSourceTrigger = UpdateSourceTrigger.Explicit,
					XPath = "ExpectedXPath"
				};
				Assert.IsNotNull(validationBinding.AsyncState);
				Assert.IsTrue(validationBinding.BindsDirectlyToSource);
				Assert.IsNotNull(validationBinding.Context);
				Assert.IsNotNull(validationBinding.Converter);
				Assert.IsNotNull(validationBinding.ConverterCulture);
				Assert.IsNotNull(validationBinding.ConverterParameter);
				Assert.IsNotNull(validationBinding.ElementName);
				Assert.IsNotNull(validationBinding.FallbackValue);
				Assert.IsTrue(validationBinding.IsAsync);
				Assert.AreEqual(BindingMode.OneTime, validationBinding.Mode);
				Assert.IsTrue(validationBinding.NotifyOnTargetUpdated);
				Assert.IsFalse(validationBinding.NotifyOnValidationError);
				Assert.IsNotNull(validationBinding.Path);
				Assert.IsNull(validationBinding.RelativeSource);
				Assert.IsNotNull(validationBinding.RuleSet);
				Assert.IsNull(validationBinding.Source);
				Assert.IsNotNull(validationBinding.UpdateSourceExceptionFilter);
				Assert.AreEqual(UpdateSourceTrigger.Explicit, validationBinding.UpdateSourceTrigger);
				Assert.AreEqual(0, validationBinding.ValidationRules.Count);
				Assert.IsNotNull(validationBinding.XPath);
			}
			[Test]
			public void NonDefaultSource()
			{
				var validationBinding = new ValidationBinding
				{
					AsyncState = new object(),
					BindsDirectlyToSource = true,
					Context = new object(),
					Converter = new BooleanToVisibilityConverter(),
					ConverterCulture = CultureInfo.CurrentCulture,
					ConverterParameter = new object(),
					FallbackValue = new object(),
					IsAsync = true,
					Mode = BindingMode.OneTime,
					NotifyOnTargetUpdated = true,
					NotifyOnValidationError = false,
					Path = new PropertyPath("ExpectedPath"),
					RuleSet = "ExpectedRuleSet",
					Source = new object(),
					UpdateSourceExceptionFilter = CallBack,
					UpdateSourceTrigger = UpdateSourceTrigger.Explicit,
					XPath = "ExpectedXPath"
				};
				Assert.IsNotNull(validationBinding.AsyncState);
				Assert.IsTrue(validationBinding.BindsDirectlyToSource);
				Assert.IsNotNull(validationBinding.Context);
				Assert.IsNotNull(validationBinding.Converter);
				Assert.IsNotNull(validationBinding.ConverterCulture);
				Assert.IsNotNull(validationBinding.ConverterParameter);
				Assert.IsNull(validationBinding.ElementName);
				Assert.IsNotNull(validationBinding.FallbackValue);
				Assert.IsTrue(validationBinding.IsAsync);
				Assert.AreEqual(BindingMode.OneTime, validationBinding.Mode);
				Assert.IsTrue(validationBinding.NotifyOnTargetUpdated);
				Assert.IsFalse(validationBinding.NotifyOnValidationError);
				Assert.IsNotNull(validationBinding.Path);
				Assert.IsNull(validationBinding.RelativeSource);
				Assert.IsNotNull(validationBinding.RuleSet);
				Assert.IsNotNull(validationBinding.Source);
				Assert.IsNotNull(validationBinding.UpdateSourceExceptionFilter);
				Assert.AreEqual(UpdateSourceTrigger.Explicit, validationBinding.UpdateSourceTrigger);
				Assert.AreEqual(0, validationBinding.ValidationRules.Count);
				Assert.IsNotNull(validationBinding.XPath);
			}

			private static object CallBack(object bindExpression, Exception exception)
			{
				throw new NotImplementedException();
			}
		}

		[TestFixture]
		public class AddErrorDisplayStrategy
		{

			[Test]
			[ExpectedException(typeof(ArgumentNullException))]
			public void ExceptionNullStrategy()
			{
				ValidationBinding.DisplayStrategies.AddStrategy(null);
			}
			[Test]
			public void Simple()
			{
				var mockErrorDisplayStrategy = new MockErrorDisplayStrategy();
				ValidationBinding.DisplayStrategies.AddStrategy(mockErrorDisplayStrategy);
				Assert.IsTrue(ValidationBinding.DisplayStrategies.Contains(mockErrorDisplayStrategy));
			}
		}

		[TestFixture]
		public class RemoveErrorDisplayStrategy
		{

			[Test]
			[ExpectedException(typeof(ArgumentNullException))]
			public void ExceptionNullStrategy()
			{
				ValidationBinding.DisplayStrategies.RemoveStrategy(null);
			}
			[Test]
			public void Simple()
			{

				ValidationBinding.DisplayStrategies.Clear();
				var mockErrorDisplayStrategy = new MockErrorDisplayStrategy();
				ValidationBinding.DisplayStrategies.AddStrategy(mockErrorDisplayStrategy);
				Assert.IsTrue(ValidationBinding.DisplayStrategies.Contains(mockErrorDisplayStrategy));
				ValidationBinding.DisplayStrategies.RemoveStrategy(mockErrorDisplayStrategy);
				Assert.IsFalse(ValidationBinding.DisplayStrategies.Contains(mockErrorDisplayStrategy));

			}
		}

		public class MockErrorDisplayStrategy : IErrorDisplayStrategy
		{


			public void DisplayError(BindingExpressionBase bindingExpressionBase, FrameworkElement frameworkElement, string errorMessage)
			{
				throw new NotImplementedException();
			}

			public void ClearError(FrameworkElement element)
			{
				throw new NotImplementedException();
			}

			public bool CanHandleTarget(FrameworkElement rule)
			{
				throw new NotImplementedException();
			}
		}
	}
}
